package net.ikenway.springboot.demo.Service.Implement;

import com.google.gson.Gson;
import net.ikenway.springboot.demo.Model.Dto.UserDto;
import net.ikenway.springboot.demo.Model.Dto.WechatOAuthResponseDto;
import net.ikenway.springboot.demo.Model.Entity.User;
import net.ikenway.springboot.demo.Utils.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.token.Sha512DigestUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.persistence.EntityExistsException;

/**
 * @author MasterKenway <zk@ikenway.net>
 * @Description
 * @date Created Date 12/13/2020
 */
@Service
public class AuthenticationService {

    @Value("${wechat.clientId}")
    private String clientId;

    @Value("${wechat.clientSecret}")
    private String clientSecret;

    private static final String WECHAT_CODE_TO_SESSION = "https://api.weixin.qq.com/sns/jscode2session?grant_type=authorization_code";


    private final AuthenticationManager authenticationManager;

    private final UserDetailsService userService;

    private final JwtTokenUtil jwtTokenUtil;

    @Autowired
    public AuthenticationService(AuthenticationManager authenticationManager,
                                 @Qualifier("userDetailsServiceImpl") UserDetailsService userService,
                                 JwtTokenUtil jwtTokenUtil) {
        this.authenticationManager = authenticationManager;
        this.userService = userService;
        this.jwtTokenUtil = jwtTokenUtil;
    }

    public void register(String username, String password) throws EntityExistsException {
        UserDetailsServiceImpl userDetailsService = (UserDetailsServiceImpl) this.userService;
        try {
            userDetailsService.findByUsername(username);
            throw new EntityExistsException();
        } catch (UsernameNotFoundException usernameNotFoundException) {
            User user = new User(username, Sha512DigestUtils.shaHex(password));
            userDetailsService.create(user);
        }
    }

    public String login(String username, String password) throws UsernameNotFoundException, BadCredentialsException, DisabledException, Exception {
        String token = null;
        UserDetails userDetails = this.userService.loadUserByUsername(username);
        for (GrantedAuthority authority: userDetails.getAuthorities()) {
            if (authority.getAuthority().equals("CUSTOMER")) throw new Exception("无权限访问");
        }
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
        Authentication authentication = this.authenticationManager.authenticate(authenticationToken);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        token = this.jwtTokenUtil.generateToken(userDetails);
        return token;
    }

    public String loginByWechat(String username, String password) {
        String token = null;
        UserDetailsServiceImpl userDetailsService = (UserDetailsServiceImpl) this.userService;
        UserDetails userDetails = this.userService.loadUserByUsername(username);
        User user = userDetailsService.findByUsername(username);
        user.setPassword(Sha512DigestUtils.shaHex(password));
        userDetailsService.update(user);
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
        Authentication authentication = this.authenticationManager.authenticate(authenticationToken);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        token = this.jwtTokenUtil.generateToken(userDetails);
        return token;
    }

    public WechatOAuthResponseDto wechatCode2Session(String code) {
        Gson gson = new Gson();

        RestTemplate restTemplate = new RestTemplate();

        RequestEntity<Void> requestEntity = RequestEntity.get(WECHAT_CODE_TO_SESSION + "&appid=" +
                clientId + "&secret=" + clientSecret + "&js_code=" + code + "").build();

        ResponseEntity<String> responseEntity = restTemplate.exchange(requestEntity, String.class);

        return gson.fromJson(responseEntity.getBody(), WechatOAuthResponseDto.class);
    }
}
